import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.sql.SQLException;

import com.multitrack.datatype.Event;
import com.multitrack.datatype.EventData;
import com.multitrack.datatype.GPS;
import com.multitrack.datatype.MyLocation;
import com.multitrack.datatype.SocketMessage;
import com.multitrack.datatype.TrackSelectArg;
import com.multitrack.datatype.UserInfo;
import com.multitrack.sql.Sql;

public class Server {

	private ServerSocket serverSocket;
	private final int PORT;
	private final int BLACKLOG;

	public Server() {
		// PORT = 1203;
		// port = 1204;
		PORT = 1205;
		BLACKLOG = 10;
	}

	public Server(int port) {
		this.PORT = port;
		this.BLACKLOG = 5;
	}

	void run() {
		try {

			serverSocket = new ServerSocket(PORT, BLACKLOG);
			System.out.println("[Multi-Tracking Server]");
			while (true) {
				Socket connection = serverSocket.accept();
				new ClientProcessThread(connection).start();
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	class ClientProcessThread extends Thread {

		private Socket connection;
		private int port;
		private ObjectInputStream in;
		private ObjectOutputStream out;

		public ClientProcessThread(Socket connection) {
			this.connection = connection;
			this.port = connection.getPort();
		}

		public void run() {
			try {
				System.out.println("[BEGIN]");
				processMysql();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				close();
				System.out.println("[END]\n");
			}
		}

		private void sendMessage(Object object) throws IOException {
			out.writeObject(object);
			out.flush();
		}

		/**
		 * @throws IOException
		 * @throws ClassNotFoundException
		 * @throws SQLException 
		 * 
		 */
		private void processMysql() throws IOException, ClassNotFoundException, SQLException {
			in = new ObjectInputStream(connection.getInputStream());
			out = new ObjectOutputStream(connection.getOutputStream());
			out.flush();

			SocketMessage msg = (SocketMessage) in.readObject();
			Sql sql = new Sql(port, msg);

			System.out.print(port + ": ");
			msg.print();
			sql.connect();

			String event_id;
			EventData em_id;
			Event event;

			switch (msg) {

			case IS_MEMBER:
				String member_id = (String) in.readObject();
				sendMessage(sql.checkId(member_id));
				break;

			case APP_JOIN:
				UserInfo info = (UserInfo) in.readObject();
				sendMessage(sql.appJoin(info));
				break;

			case REQUEST_EVENT_LIST:
				sendMessage(sql.responseEventList());
				break;

			case CREATE_EVENT:
				event = (Event) in.readObject();
				sendMessage(sql.executeCreateEventTransaction(event));
				break;

			case RECORD_LOCATION:
				MyLocation myLoc = (MyLocation) in.readObject();
				sendMessage(sql.recordLocation(myLoc));

				break;

			case REQUEST_ALL_MEMBER_CURRENT_LOCATION:
				event_id = (String) in.readObject();
				sendMessage(sql.responseAllMemberCurrLoc(event_id));
				break;

			case REQUEST_EVENT_INFO:
				EventData data = (EventData) in.readObject();
				sendMessage(sql.responseEventInfo(data));
				break;

			case REQUEST_MEMBER_LIST:
				event_id = (String) in.readObject();
				sendMessage(sql.responseMemberList(event_id));
				break;

			case REQUEST_MEMBER_TRACK:
			case REQUEST_MEMBER_TRACK_MOVE:
				TrackSelectArg trackArg = (TrackSelectArg) in.readObject();
				sendMessage(sql.responseMemberTrack(trackArg));
				break;

			case CURR_LOCATION:
				em_id = (EventData) in.readObject();
				sendMessage(sql.responseMoveLocation(em_id));
				break;

			case SEND_DESTINATION:
				GPS destGPS = (GPS) in.readObject();
				sendMessage(sql.setDestination(destGPS));
				break;

			case CHANGE_LEADER:
				event = (Event) in.readObject();
				sendMessage(sql.responseChangeLeader(event));
				break;

			case BAN_MEMBER:
				em_id = (EventData) in.readObject();
				sendMessage(sql.executeBanMemberTransaction(em_id));
				break;

			case EVENT_JOIN:
				EventData ed = (EventData) in.readObject();
				sendMessage(sql.joinEvent(ed));
				break;

			case IS_IN_EVENT:
				member_id = (String) in.readObject();
				sendMessage(sql.checkEventMember(member_id));
				break;

			case EVENT_QUIT:
				EventData quitData = (EventData) in.readObject();
				sendMessage(sql.eventQuit(quitData));
				break;

			case CLEAR_MEMBER:
				sql.memberClear();
				SocketMessage.CLEAR_MEMBER.print();
				break;

			default:
				SocketMessage.ERROR.print();
				break;

			}
		}

		/**
		 * 
		 */
		private void close() {
			try {
				if (out != null)
					out.close();
				if (in != null)
					in.close();
				if (connection != null)
					connection.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String args[]) {
		Server server = new Server();
		server.run();
	}
}